package com.liuyi.netty.im.server.config;

import com.liuyi.netty.im.commons.codes.CodeConst;
import com.liuyi.netty.im.commons.codes.serialize.ContentTypeSerializeManage;
import com.liuyi.netty.im.server.handle.LimComandService;
import com.liuyi.netty.im.server.handle.cluster.ClusterMessageDisposeManage;
import com.liuyi.netty.im.server.handle.cluster.ClusterSend;
import com.liuyi.netty.im.server.handle.cluster.impl.DefaultClusterSend;
import com.liuyi.netty.im.server.handle.cluster.impl.dispose.ChannelIdClusterMessageDispose;
import com.liuyi.netty.im.server.handle.cluster.impl.dispose.UserClusterMessageDispose;
import com.liuyi.netty.im.server.handle.message.SendMessageProcessor;
import com.liuyi.netty.im.server.handle.pipeline.LoginProcessor;
import com.liuyi.netty.im.server.handle.pipeline.LogoutProcessor;
import com.liuyi.netty.im.server.handle.service.MessageListener;
import com.liuyi.netty.im.server.handle.service.MessageService;
import com.liuyi.netty.im.server.handle.service.RelationChainService;
import com.liuyi.netty.im.server.handle.service.SessionService;
import com.liuyi.netty.im.server.handle.storage.UserStorage;
import com.liuyi.netty.im.server.handle.storage.impl.DefaultUserStorage;
import com.liuyi.netty.im.server.util.ThreadFactoryImpl;
import lombok.Data;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 全局控制器
 *
 * @author Mr.Fmy
 * @since 2021-11-26
 */
@Data
public class LimController {

    private final RelationChainService relationChainService;
    private final SessionService sessionService;
    private final MessageService messageService;
    private final MessageListener messageListener;
    private final UserStorage userStorage;
    private final SendMessageProcessor sendMessageProcessor;
    private final ClusterSend clusterSend;

    public LimController(RelationChainService relationChainService, SessionService sessionService, MessageService messageService, MessageListener messageListener) {
        ThreadPoolExecutor defaultClusterSendThreadPoolExecutor = new ThreadPoolExecutor(2, 4, 3000,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new ThreadFactoryImpl("DefaultClusterSend"));
        this.sessionService = sessionService;
        this.messageService = messageService;
        this.messageListener = messageListener;
        this.relationChainService = relationChainService;
        this.userStorage = new DefaultUserStorage();
        this.sendMessageProcessor = new SendMessageProcessor(messageListener);
        this.clusterSend = new DefaultClusterSend(this.sendMessageProcessor, defaultClusterSendThreadPoolExecutor);
        init();
    }

    private void init() {
        LimManage.setRelationChainService(this.relationChainService);
        LimManage.setSessionService(this.sessionService);
        LimManage.setMessageService(this.messageService);
        LimManage.setMessageListener(this.messageListener);
        LimManage.setUserStorage(this.userStorage);
        LimManage.setSendMessageProcessor(this.sendMessageProcessor);
        LimManage.setClusterSend(this.clusterSend);

        //集群消息接收处理注册
        ClusterMessageDisposeManage.registered(CodeConst.EventToType.USER, new UserClusterMessageDispose());
        ClusterMessageDisposeManage.registered(CodeConst.EventToType.CHANNELID, new ChannelIdClusterMessageDispose());

        //消息类型序列化映射
        ContentTypeSerializeManage.registered(CodeConst.CONTENT_TYPE_JSON, new ContentTypeSerializeManage.FastJson());

        ThreadPoolExecutor loginProcessorThreadPoolExecutor = new ThreadPoolExecutor(2, 4, 3000,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(100000), new ThreadFactoryImpl("LoginProcessor"));

        ThreadPoolExecutor logoutProcessorThreadPoolExecutor = new ThreadPoolExecutor(2, 4, 3000,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(100000), new ThreadFactoryImpl("LogoutProcessor"));
        //消息命令 channel处理器
        LimComandService.put(CodeConst.Command.LOGIN, new LoginProcessor(this), loginProcessorThreadPoolExecutor);
        LimComandService.put(CodeConst.Command.LOGOUT, new LogoutProcessor(this), logoutProcessorThreadPoolExecutor);
    }
}
